package references

import (
	"lesson01/instructions/base"
	"lesson01/rtda"
	"lesson01/rtda/heap"
)

//0xB9 0x00 0x02 0x01 0x00
//0xB9：是 invoke_interface 指令的操作码（opcode）
//0x00 0x02：是 <indexbyte1> 和 <indexbyte2>，组合起来是 0x0002，即索引值为 2。
//0x01：是 <count>，表示参数个数。
//0x00：是填充字节。

type InvokeInterface struct {
	index uint
}

func (e *InvokeInterface) FetchOperands(reader *base.BytecodeReader) {
	e.index = uint(reader.ReadUint16())
	reader.ReadUint8()
	reader.ReadUint8()
}

func (e *InvokeInterface) Execute(frame *rtda.Frame) {
	cp := frame.Method().Class().ConstantPool()
	methodRef := cp.GetConstant(e.index).(*heap.InterfaceMethodRef)
	resolvedMethod := methodRef.ResolveInterfaceMethod()
	if resolvedMethod.IsStatic() || resolvedMethod.IsPrivate() {
		panic("java.lang.IncompatibleClassChangeError")
	}

	ref := frame.OperandStack().GetRefFromTop(resolvedMethod.ArgSlotCount() - 1)
	if ref == nil {
		panic("java.lang.NullPointerException")
	}

	if !ref.Class().IsImplements(methodRef.ResolvedClass()) {
		panic("java.lang.IncompatibleClassChangeError")
	}

	methodToBeInvoked := heap.LookupMethodInClass(ref.Class(), methodRef.Name(), methodRef.Descriptor())
	if methodToBeInvoked == nil || methodToBeInvoked.IsAbstract() {
		panic("java.lang.AbstractMethodError")
	}

	if !methodToBeInvoked.IsPublic() {
		panic("java.lang.IllegalAccessError")
	}

	base.InvokeMethod(frame, methodToBeInvoked)
}
